package com.miplus.ccrm.core.service.voiceprint;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.yulichang.base.MPJBaseServiceImpl;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.Unirest;
import com.miplus.ccrm.common.*;
import com.miplus.ccrm.core.controller.vo.credit.CrdCardResVo;
import com.miplus.ccrm.core.controller.vo.file.UploadResVo;
import com.miplus.ccrm.core.controller.vo.voiceprint.*;
import com.miplus.ccrm.core.pojo.ConCustomer;
import com.miplus.ccrm.core.pojo.FiTaskOldhist;
import com.miplus.ccrm.core.pojo.VoiceModelLibrary;
import com.miplus.ccrm.core.pojo.VoicePrintLibrary;
import com.miplus.ccrm.core.security.JCommonData;
import com.miplus.ccrm.core.service.cust.ConCustomerService;
import com.miplus.ccrm.core.service.voiceprint.VoiceModelLibraryService;
import com.miplus.ccrm.core.mapper.VoiceModelLibraryMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.*;

/**
* @author Yaohui
* @description 针对表【voice_model_library(客户语音模型库表)】的数据库操作Service实现
* @createDate 2025-03-01 14:09:33
*/
@Slf4j
@Service
public class VoiceModelLibraryServiceImpl extends MPJBaseServiceImpl<VoiceModelLibraryMapper, VoiceModelLibrary>
    implements VoiceModelLibraryService{

    // 本地上传文件的路径
    @Value("${voice.library.upload.filepath}")
    public String uploadPath;

    @Value("${voice.library.upload.filetype}")
    private String uploadFileType;

    @Value("${voice.library.upload.filesize}")
    private Integer uploadFileSize;

    // ng地址 代理了 uploadPath
    @Value("${voice.library.recfile.url}")
    private String rec_fileurl;

    @Value("${uploadfiles.type}")
    private String uploadType;

//    @Value("${api.url}")
//    private String apiUrl;
//    @Value("${nginx.url}")
//    private String nginxUrl;
    @Resource
    private ConCustomerService conCustomerService;

    @Resource
    private VoicelibraryService voicelibraryService;

    @Resource
    private VoicePrintLibraryService printLibraryService;

    @Resource
    private JCommonData jCommonData;

    @Override
    public IPage<CustomerModelPageResVo> customerModelPage(JSysUser user,CustomerModelPageReqVo reqVo) {
        boolean enviewall= JUsrPerm.viewAllFiCase(user);
        String $usrid=user.getUsrid();

        return conCustomerService.selectJoinListPage(new Page<>(reqVo.getPageNum(),reqVo.getPageSize()),
                CustomerModelPageResVo.class,
                new MPJLambdaWrapper<ConCustomer>()
                        .exists(!enviewall,String.format("select 1 from fi_creditcases fi where fi.customernumber=t.customernumber and (fi.sendtousr='%s' or fi.sendtodept in(select grm.grpid from sys_grpmgr grm where grm.grpmanagerid='%s'))",$usrid,$usrid))
                        .leftJoin(VoiceModelLibrary.class,"vml",VoiceModelLibrary::getCustomerId,ConCustomer::getCustomernumber)
                        .selectAs(ConCustomer::getCustomernumber,CustomerModelPageResVo::getCustomerId)
                        .selectAs("fun_getnames('VOICEPRINT.MODEL.STATUS',if(vml.status is null,1,vml.status))", CustomerModelPageResVo::getStatusDsc)
                        .selectAs(ConCustomer::getCustname,CustomerModelPageResVo::getCustomerName)
                        .select(VoiceModelLibrary::getStatus,
                                VoiceModelLibrary::getLastTrainTime,
                                VoiceModelLibrary::getVoiceprintLibraryCount
                        )
                        .eq(JPubUtils.IsNotEmpty(reqVo.getCustomerId()),ConCustomer::getCustomernumber,reqVo.getCustomerId())
                        .eq(JPubUtils.IsNotEmpty(reqVo.getStatus()),VoiceModelLibrary::getStatus,reqVo.getStatus())
                        .between(JPubUtils.IsNotEmpty(reqVo.getFileSizeS()), VoiceModelLibrary::getVoiceprintLibraryCount,JPubUtils.IsNotEmpty(reqVo.getFileSizeS()),JPubUtils.IsNotEmpty(reqVo.getFileSizeE()))
                        .orderByDesc(ConCustomer::getCreateddate)
        );
    }

    @Override
    public CustomerModelInfoResVo customerModelInfo(CustomerModelInfoReqVo reqVo) {
        if(addCustomerModel(reqVo.getCustomerId())>0){
            return baseMapper.selectJoinOne(CustomerModelInfoResVo.class,
                    new MPJLambdaWrapper<>(VoiceModelLibrary.class)
                            .selectAs(VoiceModelLibrary::getCustomerId,CustomerModelInfoResVo::getCustomerId)
                            .selectAs(VoiceModelLibrary::getCustomerName,CustomerModelInfoResVo::getCustomerName)
                            .eq(VoiceModelLibrary::getCustomerId,reqVo.getCustomerId())
            );
        }
        return new CustomerModelInfoResVo();
    }

    @Transactional
    @Override
    public CmdResVo trainModel(CustomerModelInfoReqVo reqVo) {
        CmdResVo resVo=new CmdResVo();
        VoiceModelLibrary dbModelLibrary = getById(reqVo.getCustomerId());

        log.info("dbModelLibrary.getVoiceprintCount():"+dbModelLibrary.getVoiceprintCount());
        // 检查 当前声纹条数
        if(dbModelLibrary.getVoiceprintCount()==0){
            throw new ServiceException(EnumRCode.TrainModelError.value, EnumRCode.TrainModelError.name);
        }

        int trainmodel = voicelibraryService.trainmodel(reqVo.getCustomerId());
        if(trainmodel!=0){
            lambdaUpdate()
                    .set(VoiceModelLibrary::getStatus,3)
                    .eq(VoiceModelLibrary::getCustomerId,reqVo.getCustomerId())
                    .update();
//            throw new ServiceException(EnumRCode.TrainModelError.value, EnumRCode.TrainModelError.name);
        }

        printLibraryService.lambdaUpdate()
                .set(VoicePrintLibrary::getIsParticipate,1)
                .eq(VoicePrintLibrary::getBusinessId,reqVo.getCustomerId())
                .update();

        lambdaUpdate()
                .set(VoiceModelLibrary::getStatus,2)
                .set(VoiceModelLibrary::getLastTrainTime,new Date())
                .eq(VoiceModelLibrary::getCustomerId,reqVo.getCustomerId())
                .update();

        resVo.setCount(1);
        resVo.setKeyId(String.valueOf(trainmodel));
        return resVo;
    }

    @Override
    public int addCustomerModel(String customerId) {
        //验证用户信息
        ConCustomer dbCustomer = conCustomerService.getById(customerId);
        if(dbCustomer!=null){
            VoiceModelLibrary dbVoiceModelLibrary= baseMapper.selectById(customerId);
            if(dbVoiceModelLibrary==null){
                VoiceModelLibrary voiceModelLibrary=new VoiceModelLibrary();
                voiceModelLibrary.setCustomerId(customerId);
                voiceModelLibrary.setCustomerName(dbCustomer.getCustname());
                voiceModelLibrary.setStatus(1);
                voiceModelLibrary.setModelType(1);
                return baseMapper.insert(voiceModelLibrary);
            }else {
                return 1;
            }
        }
        return 0;
    }

    @Override
    public CmdResVo verifyModel(String id) {
        CmdResVo resVo=new CmdResVo();
        VoicePrintLibrary dbPrintLibrary = printLibraryService.getById(id);

        if (dbPrintLibrary==null){
            throw new ServiceException(EnumRCode.NoData.value, EnumRCode.NoData.name);
        }

        VoiceModelLibrary voiceModelLibrary = baseMapper.selectById(dbPrintLibrary.getBusinessId());
        if(voiceModelLibrary.getStatus()!=2){
            throw new ServiceException(EnumRCode.ModelError.value, EnumRCode.ModelError.name);
        }

        try {
            if(dbPrintLibrary.getVoiceprintType()==2){
                //进行文件校验
                String filename = dbPrintLibrary.getFilename();
                String url = dbPrintLibrary.getFilepath() + '/' + filename;
                Path filePath = Paths.get(uploadPath+url);
                log.info("filePath():{}",filePath);
                if (!Files.exists(filePath)) {
                    throw new ServiceException(EnumRCode.FileError.value, EnumRCode.FileError.name);
                }
                // 创建 File 对象
                File file = new File(filePath.toUri());
                Double verifymodel = voicelibraryService.verifymodel(dbPrintLibrary.getBusinessId(), file);
                if(verifymodel<0){
                    verifymodel=0.0;
                }
                    log.info("verifymodel:{}",verifymodel);
                    printLibraryService.lambdaUpdate()
                            .set(VoicePrintLibrary::getScore,verifymodel)
                            .eq(VoicePrintLibrary::getId,id)
                            .update();
                    log.info("success");
                    resVo.setKeyId("1");
                    resVo.setCount(1);
            }
        } catch (ServiceException e) {
            throw new RuntimeException(e);
        }
        return resVo;
    }


    @Override
    public IPage<VoicePrintLibraryPageResVo> vpPage(VoicePrintLibraryPageReqVo reqVo) {
        return printLibraryService.selectJoinListPage(new Page<>(reqVo.getPageNum(),reqVo.getPageSize()),
                VoicePrintLibraryPageResVo.class,
                new MPJLambdaWrapper<>(VoicePrintLibrary.class)
                        .select(VoicePrintLibrary::getId,
                                VoicePrintLibrary::getBusinessId,
                                VoicePrintLibrary::getBusinessType,
                                VoicePrintLibrary::getStatus,
                                VoicePrintLibrary::getScore,
                                VoicePrintLibrary::getIsParticipate,
                                VoicePrintLibrary::getVoiceprintName,
                                VoicePrintLibrary::getVoiceprintType,
                                VoicePrintLibrary::getCreateTime
                        )
                        .eq(VoicePrintLibrary::getBusinessId,reqVo.getBusinessId())
                        .eq(VoicePrintLibrary::getVoiceprintType,reqVo.getVoiceprintType())
        );
    }

    @Transactional
    @Override
    public CmdResVo customerVoiceRegi(CustomerVoiceRegiReqVo reqVo) {
        CmdResVo resVo = new CmdResVo();

        if(reqVo.getUploadResVoList()==null || reqVo.getUploadResVoList().size()==0){
            throw new ServiceException(EnumRCode.FileUploadErr.value, EnumRCode.FileUploadErr.name);
        }

        DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("yyyyMMdd");
        String fileDatePath = LocalDate.now().format(dateFormatter);

        VoiceModelLibrary dbModelLibrary = getById(reqVo.getCustomerId());

        if(dbModelLibrary==null){
            throw new ServiceException(EnumRCode.NoData.value, EnumRCode.NoData.name);
        }
        int count=dbModelLibrary.getVoiceprintCount();
        Integer step=count+1;

        List<UploadResVo> uploadResVoList = reqVo.getUploadResVoList();

        int icount=0;
        for (UploadResVo uploadResVo : uploadResVoList) {

            String filename = uploadResVo.getFilename();
            String url = "/" + fileDatePath + '/' + filename;
            Path filePath = Paths.get(uploadPath+url);
            log.info("filePath():{}",filePath);
            if (!Files.exists(filePath)) {
                throw new ServiceException(EnumRCode.FileUploadErr.value, EnumRCode.FileUploadErr.name);
            }

            // 创建 File 对象
            File file = new File(filePath.toUri());
            int i = voicelibraryService.addSample(reqVo.getCustomerId(), step, file);
            if(i==0){
                // 记录声纹地址
                VoicePrintLibrary voicePrintLibrary=new VoicePrintLibrary();
                voicePrintLibrary.setBusinessId(reqVo.getCustomerId());
                voicePrintLibrary.setBusinessType(1);
                voicePrintLibrary.setStatus(10);
                voicePrintLibrary.setIsParticipate(0);
                voicePrintLibrary.setVoiceprintName(uploadResVo.getOrifilename());
                voicePrintLibrary.setVoiceprintType(1);
                voicePrintLibrary.setRecorderid(uploadResVo.getIpaddr());
                voicePrintLibrary.setFilename(uploadResVo.getFilename());
                voicePrintLibrary.setFilepath("/"+fileDatePath);
                voicePrintLibrary.setOrifilename(uploadResVo.getOrifilename());
                printLibraryService.save(voicePrintLibrary);
                resVo.setCount(icount++);
                resVo.setKeyId("ok");
            }
            step++;
        }

        upadetCount(reqVo.getCustomerId());
        return resVo;
    }

    @Override
    public CmdResVo customerCompareRegi(CustomerVoiceRegiReqVo reqVo) {
        CmdResVo resVo = new CmdResVo();

        if(reqVo.getUploadResVoList()==null || reqVo.getUploadResVoList().size()==0){
            throw new ServiceException(EnumRCode.FileUploadErr.value, EnumRCode.FileUploadErr.name);
        }
        DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("yyyyMMdd");
        String fileDatePath = LocalDate.now().format(dateFormatter);

        VoiceModelLibrary dbModelLibrary = getById(reqVo.getCustomerId());

        if(dbModelLibrary==null || dbModelLibrary.getStatus()!=2){
            throw new ServiceException(EnumRCode.ModelError.value, EnumRCode.ModelError.name);
        }

        List<UploadResVo> uploadResVoList = reqVo.getUploadResVoList();

        int icount=0;
        for (UploadResVo uploadResVo : uploadResVoList) {

//            String filename = uploadResVo.getFilename();
//            String url = "/" + fileDatePath + '/' + filename;
//            Path filePath = Paths.get(uploadPath+url);
//            log.info("filePath():{}",filePath);
//            if (!Files.exists(filePath)) {
//                throw new ServiceException(EnumRCode.FileUploadErr.value, EnumRCode.FileUploadErr.name);
//            }

            // 记录声纹地址
            VoicePrintLibrary voicePrintLibrary=new VoicePrintLibrary();
            voicePrintLibrary.setBusinessId(reqVo.getCustomerId());
            voicePrintLibrary.setBusinessType(1);
            voicePrintLibrary.setStatus(10);
            voicePrintLibrary.setIsParticipate(0);
            voicePrintLibrary.setVoiceprintName(uploadResVo.getOrifilename());
            voicePrintLibrary.setVoiceprintType(2);
            voicePrintLibrary.setRecorderid(uploadResVo.getIpaddr());
            voicePrintLibrary.setFilename(uploadResVo.getFilename());
            voicePrintLibrary.setFilepath("/"+fileDatePath);
            voicePrintLibrary.setOrifilename(uploadResVo.getOrifilename());
            printLibraryService.save(voicePrintLibrary);
            resVo.setCount(icount++);
            resVo.setKeyId("ok");

            // 声纹识别
            this.verifyModel(String.valueOf(voicePrintLibrary.getId()));
        }

        // 更新总数
        lambdaUpdate()
                .set(VoiceModelLibrary::getVoiceprintLibraryCount,
                        printLibraryService.selectJoinCount(new MPJLambdaWrapper<>(VoicePrintLibrary.class)
                                .eq(VoicePrintLibrary::getBusinessId,reqVo.getCustomerId())
                        ))
                .eq(VoiceModelLibrary::getCustomerId,reqVo.getCustomerId()).update();

        return resVo;
    }

    @Transactional
    @Override
    public CmdResVo vpDel(String id) {
        CmdResVo resVo=new CmdResVo();
        VoicePrintLibrary printLibrary = printLibraryService.getById(id);

        printLibraryService.removeById(id);
        resVo.setCount(1);

        upadetCount(printLibrary.getBusinessId());
        return resVo;
    }

    @Override
    public void OnPlayFile(String id, HttpServletResponse response) {
        String urlbody=rec_fileurl;

        // 获取 id
        VoicePrintLibrary printLibrary = printLibraryService.getById(id);
        String recipaddr= printLibrary.getFilepath()+"/"+printLibrary.getFilename();

        urlbody=urlbody+recipaddr;
        log.info("urlBody:{}",urlbody);
        try {
            HttpResponse<InputStream> inputResponse = Unirest.get(urlbody).asBinary();
            InputStream fis = inputResponse.getBody();
            response.addHeader("Content-Type","audio/mpeg;charset=utf-8");
            ServletOutputStream out = response.getOutputStream();
            int len_l = 0,totalcnt=0;
            byte[] buf = new byte[1024];
            while ((len_l = fis.read(buf)) != -1) {
                totalcnt+=len_l;
                out.write(buf, 0, len_l);
            }
            out.flush();
            out.close();
            fis.close();

            log.info("OnPlayLocalRecord.totalcnt={}",totalcnt);
        } catch (Exception e) {
            log.error("OnPlayLocalRecord.Err:",e);
        }

    }
    @Override
    public UploadResVo doUpload(MultipartFile file) {
        String fileName="";
        if (file.isEmpty()) {
            throw new ServiceException(EnumRCode.FileNull.value, EnumRCode.FileNull.name);
        } else {
            long size = file.getSize(); //校验文件大小
            fileName = file.getOriginalFilename();
            log.info("Upload:fileName={},size={} to {}",fileName,size,uploadType);
            String type = fileName.substring(fileName.lastIndexOf('.') + 1);
            String[] fileType = uploadFileType.split(",");
            if (!Arrays.asList(fileType).contains(type)) {
                throw new ServiceException(EnumRCode.FileTypeErr.value, EnumRCode.FileTypeErr.name);
            } else if (size > 1024 * 1024 * uploadFileSize) {
                throw new ServiceException(EnumRCode.FileSizeOver.value, EnumRCode.FileSizeOver.name);
            }
        }
        UploadResVo resVo=null;
        if(JPubUtils.IsEqual(uploadType,"xsky")){
//            resVo = UploadXSky(file);
        }
        else {
            resVo = UploadLocal(file);
        }
        log.info("Upload:fileName={} Done.SetData",fileName);
        //2025-02-13 为了数据安全保存在服务端，url和文件路径值不返回客户端,默认时效60分钟
        UploadResVo rs=new UploadResVo();
        BeanUtils.copyProperties(resVo,rs);
        jCommonData.setData(fileName,rs,3600);

        resVo.setFiledir("");
        resVo.setApiurl("");

        return resVo;
    }
    public UploadResVo UploadLocal(MultipartFile file) {
        UploadResVo uploadResVo=new UploadResVo();
        String fileName = file.getOriginalFilename();   //校验文件名
        try {
            DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("yyyyMMdd");
            String fileDatePath = LocalDate.now().format(dateFormatter);
            File parentPath = new File(uploadPath + "/"+fileDatePath);
            if (!parentPath.exists()) {
                parentPath.mkdir(); //判断父路径是否存在，不存在就创建出来
            }
            Random r = new Random();
            //String newName = new Date().getTime() + r.nextInt(1000) + fileName.substring(fileName.lastIndexOf("."));
            //2023-08-03
            String newName = UUID.randomUUID() + fileName.substring(fileName.lastIndexOf("."));
            log.info("UploadLocal:uploadPath={},apiUrl={},nginxUrl={},newName={}",uploadPath,null,null,newName);
            File newFile = new File(parentPath, newName);
            file.transferTo(newFile);   //复制文件
            String realPath = newFile.getPath();
            String path = "/" + fileDatePath + '/' + newName;

            uploadResVo.setOrifilename(fileName);
            uploadResVo.setFiledir(realPath);
            uploadResVo.setIpaddr(JPubUtils.getLocalIpAddr());
            uploadResVo.setFilename(newName);
//            uploadResVo.setApiurl(apiUrl+path);
//            if(JPubUtils.IsNotEmpty(nginxUrl)) {
//                uploadResVo.setWeburl(nginxUrl + path);
//            }
        } catch (Exception e) {
            throw new ServiceException(EnumRCode.FileUploadErr.value,
                    EnumRCode.FileUploadErr.name+":"+e.getMessage()
            );
        }

        return uploadResVo;
    }
    private void upadetCount(String businessId){

        // 更新总数
        lambdaUpdate()
                .set(VoiceModelLibrary::getVoiceprintLibraryCount,
                        printLibraryService.selectJoinCount(new MPJLambdaWrapper<>(VoicePrintLibrary.class)
                                .eq(VoicePrintLibrary::getBusinessId,businessId)
                        ))
                .set(VoiceModelLibrary::getVoiceprintCount,
                        printLibraryService.selectJoinCount(new MPJLambdaWrapper<>(VoicePrintLibrary.class)
                                .eq(VoicePrintLibrary::getBusinessId,businessId)
                                .eq(VoicePrintLibrary::getVoiceprintType,1)
                        ))
                .eq(VoiceModelLibrary::getCustomerId,businessId).update();
    }
}




